// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module A_cse_ocs_dpa_aes10c_gf16_sq_scaler
	#(
	   parameter POLY1 = 3,
	   parameter BETA = 4'b1011
	)
	(
	  input logic [3:0] a,
	  output logic [3:0] o
	);

	wire [2:0] x;

	// Continuous assignments to generate x^2*BETA
	generate
	  if (POLY1 == 3) begin
	    assign o[3] = (a[1] & BETA[1]) ^ (a[0] & BETA[3]) ^ (a[3] & BETA[1]) ^ (a[2] & BETA[3])
                          ^(a[3] & BETA[0]) ^ (a[3] & BETA[3]) ^ (a[2] & BETA[2]);
	    assign o[2] = (a[1] & BETA[0]) ^ (a[0] & BETA[2]) ^ (a[2] & BETA[1]) ^ (a[1] & BETA[3])
                          ^(a[3] & BETA[2]) ^ (a[3] & BETA[0]) ^ (a[2] & BETA[2]);
	    assign o[1] = (a[0] & BETA[1]) ^ (a[2] & BETA[1]) ^ (a[1] & BETA[3]) ^ (a[3] & BETA[2])
                          ^(a[2] & BETA[0]) ^ (a[1] & BETA[2]) ^ (a[3] & BETA[2])
			  ^(a[3] & BETA[1]) ^ (a[2] & BETA[3]) ^ (a[3] & BETA[3]);
	    assign o[0] = (a[2] & BETA[0]) ^ (a[1] & BETA[2]) ^ (a[3] & BETA[2]) ^ (a[3] & BETA[1])
                          ^(a[2] & BETA[3]) ^ (a[0] & BETA[0]);
	  end
	
	  if (POLY1 == 9) begin
	    assign x[0] = BETA[3] ^ BETA[2];
            assign o[0] = ~(BETA[0] & (a[0] ^ a[2] ^ a[3])) ^ ~(BETA[3] & (a[3]))
                                    ^ ~(x[0] & (a[1] ^ a[3])) ^ ~((x[0] ^ BETA[1]) & (a[2] ^ a[3]));
            assign o[1] = ~(BETA[1] & (a[0] ^ a[2] ^ a[3])) ^ ~(BETA[0] & a[3])
                                    ^ ~(BETA[3] & (a[1] ^ a[3])) ^ ~(x[0] & (a[2] ^ a[3]));
            assign o[2] = ~(BETA[2] & (a[0] ^ a[2] ^ a[3])) ^ ~(BETA[1] & a[3])
                                    ^ ~(BETA[0] & (a[1] ^ a[3])) ^ ~(BETA[3] & (a[2] ^ a[3]));
            assign o[3] = ~(BETA[3] & (a[0] ^ a[2] ^ a[3])) ^ ~(x[0] & a[3])
                                    ^ ~((x[0]^BETA[1]) & (a[1] ^ a[3]))
                                    ^ ~((x[0]^BETA[1]^BETA[0]) & (a[2] ^ a[3]));
	  end

	  if (POLY1 == 15) begin
	    assign x[0] = BETA[3] ^ BETA[2];
            assign x[1] = BETA[3] ^ BETA[1];
       	    assign x[2] = BETA[2] ^ BETA[1];
            assign o[0] = ~(BETA[0] & (a[0] ^ a[2])) ^ ~(BETA[3] & (a[2] ^ a[3]))
                                    ^ ~(x[0] & (a[1] ^ a[2])) ^ ~(x[2] & a[2]);
            assign o[1] = ~(BETA[1] & (a[0] ^ a[2])) ^ ~((BETA[0] ^ BETA[3]) & (a[2] ^ a[3]))
                                    ^  ~(BETA[2] & (a[1] ^ a[2])) ^ ~(x[1] & a[2]);
            assign o[2] = ~(BETA[2] & (a[0] ^ a[2])) ^ ~(x[1] & (a[2] ^ a[3]))
                                    ^  ~((BETA[0] ^ BETA[2]) & (a[1] ^ a[2])) ^ ~(BETA[1] & a[2]);
            assign o[3] = ~(BETA[3] & (a[0] ^ a[2])) ^ ~(x[0] & (a[2] ^ a[3]))
                                    ^  ~(x[2] & (a[1] ^ a[2])) ^ ~((BETA[1] ^ BETA[0]) & a[2]);

	  end
	endgenerate

endmodule
	
